library_paths: Vec::new(),
library_links: Vec::new(),
cfgs: Vec::new(),
+ env: Vec::new(),
metadata: Vec::new(),
rerun_if_changed: Vec::new(),
warnings: Vec::new(),
pub library_links: Vec<String>,
/// Various `--cfg` flags to pass to the compiler
pub cfgs: Vec<String>,
+ /// Additional environment variables to run the compiler with.
+ pub env: Vec<(String, String)>,
/// Metadata to pass to the immediate dependencies
pub metadata: Vec<(String, String)>,
/// Paths to trigger a rerun of this build script.
linked_libs: &parsed_output.library_links,
linked_paths: &library_paths,
cfgs: &parsed_output.cfgs,
+ env: &parsed_output.env,
});
}
let mut library_paths = Vec::new();
let mut library_links = Vec::new();
let mut cfgs = Vec::new();
+ let mut env = Vec::new();
let mut metadata = Vec::new();
let mut rerun_if_changed = Vec::new();
let mut warnings = Vec::new();
"rustc-link-lib" => library_links.push(value.to_string()),
"rustc-link-search" => library_paths.push(PathBuf::from(value)),
"rustc-cfg" => cfgs.push(value.to_string()),
+ "rustc-env" => env.push(BuildOutput::parse_rustc_env(value, &whence)?),
"warning" => warnings.push(value.to_string()),
"rerun-if-changed" => rerun_if_changed.push(value.to_string()),
_ => metadata.push((key.to_string(), value.to_string())),
library_paths: library_paths,
library_links: library_links,
cfgs: cfgs,
+ env: env,
metadata: metadata,
rerun_if_changed: rerun_if_changed,
warnings: warnings,
}
Ok((library_paths, library_links))
}
+
+ pub fn parse_rustc_env(value: &str, whence: &str)
+ -> CargoResult<(String, String)> {
+ let mut iter = value.splitn(2, '=');
+ let name = iter.next();
+ let val = iter.next();
+ match (name, val) {
+ (Some(n), Some(v)) => Ok((n.to_owned(), v.to_owned())),
+ _ => bail!("Variable rustc-env has no value in {}: {}", whence, value),
+ }
+ }
}
/// Compute the `build_scripts` map in the `Context` which tracks what build
// also need to be sure to add any -L paths for our plugins to the
// dynamic library load path as a plugin's dynamic library may be
// located somewhere in there.
+ // Finally, if custom environment variables have been produced by
+ // previous build scripts, we include them in the rustc invocation.
if let Some(build_deps) = build_deps {
let build_state = build_state.outputs.lock().unwrap();
add_native_deps(&mut rustc, &build_state, &build_deps,
pass_l_flag, ¤t_id)?;
add_plugin_deps(&mut rustc, &build_state, &build_deps,
&root_output)?;
+ add_custom_env(&mut rustc, &build_state, &build_deps, ¤t_id)?;
}
// FIXME(rust-lang/rust#18913): we probably shouldn't have to do
}
Ok(())
}
+
+ // Add all custom environment variables present in `state` (after they've
+ // been put there by one of the `build_scripts`) to the command provided.
+ fn add_custom_env(rustc: &mut ProcessBuilder,
+ build_state: &BuildMap,
+ build_scripts: &BuildScripts,
+ current_id: &PackageId) -> CargoResult<()> {
+ for key in build_scripts.to_link.iter() {
+ let output = build_state.get(key).chain_error(|| {
+ internal(format!("couldn't find build state for {}/{:?}",
+ key.0, key.1))
+ })?;
+ if key.0 == *current_id {
+ for &(ref name, ref value) in output.env.iter() {
+ rustc.env(name, value);
+ }
+ }
+ }
+ Ok(())
+ }
}
/// Link the compiled target (often of form foo-{metadata_hash}) to the
pub linked_libs: &'a [String],
pub linked_paths: &'a [String],
pub cfgs: &'a [String],
+ pub env: &'a [(String, String)],
}
impl<'a> Message for BuildScript<'a> {
assert_that(&p.root().join("target/doc/bar/fn.bar.html"), existing_file());
}
+#[test]
+fn env_build() {
+ let build = project("builder")
+ .file("Cargo.toml", r#"
+ [package]
+ name = "builder"
+ version = "0.0.1"
+ authors = []
+ build = "build.rs"
+ "#)
+ .file("src/main.rs", r#"
+ const FOO: &'static str = env!("FOO");
+ fn main() {}
+ "#)
+ .file("build.rs", r#"
+ fn main() {
+ println!("cargo:rustc-env=FOO=foo");
+ }
+ "#);
+ assert_that(build.cargo_process("build").arg("-v"),
+ execs().with_status(0));
+}
+
+#[test]
+fn env_test() {
+ let p = project("foo")
+ .file("Cargo.toml", r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+ build = "build.rs"
+ "#)
+ .file("build.rs", r#"
+ fn main() {
+ println!("cargo:rustc-env=FOO=foo");
+ }
+ "#)
+ .file("src/lib.rs", r#"
+ pub const FOO: &'static str = env!("FOO");
+ "#)
+ .file("tests/test.rs", r#"
+ extern crate foo;
+
+ #[test]
+ fn test_foo() {
+ assert_eq!("foo", foo::FOO);
+ }
+ "#);
+ assert_that(p.cargo_process("test").arg("-v"),
+ execs().with_stderr(format!("\
+[COMPILING] foo v0.0.1 ({dir})
+[RUNNING] [..] build.rs [..]
+[RUNNING] `[..][/]build-script-build`
+[RUNNING] [..] --cfg foo[..]
+[RUNNING] [..] --cfg foo[..]
+[RUNNING] [..] --cfg foo[..]
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[RUNNING] `[..][/]foo-[..][EXE]`
+[RUNNING] `[..][/]test-[..][EXE]`
+[DOCTEST] foo
+[RUNNING] [..] --cfg foo[..]", dir = p.url()))
+ .with_stdout("
+running 0 tests
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
+
+
+running 1 test
+test test_foo ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+
+"));
+}
+
#[test]
fn flags_go_into_tests() {
let p = project("foo")
rustc-flags = \"-l z -L ./\"
", target))
.file("build.rs", "");
-
+
assert_that(p.cargo_process("build").arg("-v"),
execs().with_status(0).with_stderr("\
[COMPILING] foo v0.5.0 ([..]
e = \"\"
", target))
.file("build.rs", "");
-
+
assert_that(p.cargo_process("build").arg("-v"),
execs().with_status(0).with_stderr("\
[COMPILING] foo v0.5.0 ([..]